// 通用操作封装： src/api/server.ts
import axios from 'axios'

import {
  handleRequestHeader,
  handleConfigureAuth,
  handleAuthError,
  handleGeneralError,
  handleNetworkError,
} from './tool'
import router from '@/router'

// 请求无论成功失败时，都以 resolve 方式调用。同时，希望可以处理返回值，因此在这里封装了 clearFn 的回调函数。
type Fn = (data: FcResponse<any>) => unknown

interface IAnyObj {
  [index: string]: unknown
}

interface FcResponse<T> {
  errno: string
  errmsg: string
  data: any
  code: string | number
  extra: T
  msg: string
}

let cancelToken = axios.CancelToken //取消api
let pending = [] //声明一个数组用于存储每个ajax请求的取消函数和ajax标识
let removePending = (config) => {
  pending.find((item, i) => {
    //判断当前请求数组中是否存在相同请求地址的接口
    if (item.u === config.url + '&' + config.method) {
      pending[i].c() //执行取消方法
      pending.splice(i, 1) //把这条记录从数组中移除
      return true
    }
  })
}

axios.interceptors.request.use((config) => {
  removePending(config) //在一个ajax发送前执行一下取消操作
  config.cancelToken = new cancelToken((c) => {
    // 传入对比参数 和 取消方法
    pending.push({ u: config.url + '&' + config.method, c })
  })
  config = handleRequestHeader(config)
  config = handleConfigureAuth(config)
  return config
})

axios.interceptors.response.use(
  (response) => {
    if (response.data.code === '40001' || response.data.code === '40005') {
      // 返回登录页
      router.push('/login')
    }
    if (response.status !== 200) return Promise.reject(response.data)
    handleAuthError(response.data.code)
    handleGeneralError(response.data.code, response.data.msg)
    return response
  },
  (err) => {
    handleNetworkError(err.response.status)
    Promise.reject(err.response)
  }
)

// 针对所有接口的处理（Get）
export const Get = <T>(
  url: string,
  params: IAnyObj = {},
  clearFn?: Fn
): Promise<FcResponse<T> | undefined> =>
  new Promise((resolve) => {
    axios
      .get(url, { params })
      .then((result) => {
        let res: FcResponse<T>
        if (clearFn !== undefined) {
          res = clearFn(result.data) as unknown as FcResponse<T>
        } else {
          res = result.data as FcResponse<T>
        }
        resolve(res as FcResponse<T>)
      })
      .catch((err) => {
        resolve(err)
      })
  })

export const Post = <T>(
  url: string,
  data: IAnyObj,
  params: IAnyObj = {}
): Promise<FcResponse<T> | undefined> => {
  return new Promise((resolve) => {
    axios
      .post(url, data, { params })
      .then((result) => {
        resolve(result.data as FcResponse<T>)
      })
      .catch((err) => {
        resolve(err)
      })
  })
}

// 针对所有接口的处理通用
export const AxiosApi = <T>(
  method: string,
  url: string,
  data: IAnyObj = {},
  params: IAnyObj = {},
  responseType: any = 'json'
): Promise<FcResponse<T> | undefined> => {
  return new Promise((resolve) => {
    axios({
      method,
      url,
      data,
      params,
      responseType,
    })
      .then((result) => {
        resolve(result.data as FcResponse<T>)
      })
      .catch((err) => {
        resolve(err)
      })
  })
}

export const baseUrl = import.meta.env.VITE_BASE_URL // 接口地址
